home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Archive-tools / ql read Folder / QLTOOLS.C < prev    next >
C/C++ Source or Header  |  1992-11-14  |  11KB  |  516 lines

  1. /*
  2.  
  3. QLTOOLS 
  4.  
  5. Read a QL floppy disk
  6.  
  7. (c)1992 by Giuseppe Zanetti
  8.  
  9. Giuseppe Zanetti
  10. via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY
  11. e-mail: beppe@sabrina.dei.unipd.it
  12.  
  13. Think C adaption Roberto Avanzi
  14. via Luigi Balzan 12 - 45100 Rovigo ITALY
  15. e-mail: gandalf@sabrina.dei.unipd.it
  16.  
  17. */
  18.  
  19. #define VERSION        1.0 Sep 24 1992
  20.  
  21. #include <stdio.h>
  22. #ifdef THINK_C
  23. #include "console.h"
  24. #include <string.h>
  25. #else
  26. #include <strings.h>
  27. #endif
  28.  
  29. /* this line is neccessary since stdio.h in SUN 4.0 do not define it */
  30.  
  31. #ifndef SEEK_SET
  32. #define SEEK_SET    0
  33. #endif
  34.  
  35. FILE *f;
  36. static unsigned char b[512*3];
  37. static unsigned char b0[512*3];
  38. static unsigned char ltp[18];
  39. static unsigned char ptl[18];
  40. static unsigned long int bleod;
  41. static unsigned char byeod;
  42. static unsigned char *pdir;
  43.  
  44. static unsigned int convtable[1440];
  45.  
  46. static int gsides,gtracks,gsectors,goffset;
  47.  
  48. long int lwrd(p)
  49. unsigned char *p;
  50. {
  51.     return ( (long int) ( *(p+3) + *(p+2)*0x100 + *(p+1)*0x10000 + *(p)*0x1000000 ) );
  52. }
  53.  
  54. void cat_file(fnum)
  55. long int fnum;
  56. {
  57.     long int flen,file,blk;
  58.     int i,s,c,start,end;
  59.     char buffer[512*3];
  60.     unsigned char *base;
  61.  
  62.     flen=lwrd(pdir+fnum*64);    /* with the header */
  63.  
  64.     /* printf("cat file #%i len=%ld blocks=%ld + %d\n\n",fnum,flen,flen/(512*3),flen % (512*3)); */
  65.  
  66.     for (s=0;s<=flen/(512*3);s++)
  67.     {
  68.             for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
  69.             {
  70.         base=b0+0x4C+20+i*3;
  71.         file=(int) (*(base) * 0x10) + (int) ((*(base+1) >> 4) & 0x0F) ;
  72.         blk= (*(base+1) & 0x0F)*0x100 + *(base+2);
  73.  
  74.         /* printf("%ld/%ld\n",file,blk); */
  75.  
  76.                 if (file == fnum)
  77.         {
  78.             if (blk == s)
  79.             {
  80.                 read_block(buffer,i);
  81.  
  82.                 start=0; if (s==0) start=64;
  83.                 end=512*3; if (s==(flen/(512*3))) end=flen % (512*3);
  84.  
  85.                 for(c=start;c<end;c++) printf("%c",*(buffer+c));
  86.             }
  87.         }
  88.         }
  89.     }
  90. }
  91.  
  92. void usage(error)
  93. char *error;
  94. {
  95.     fprintf(stderr,"error %s\n\n",error);
  96.     fprintf(stderr,"Usage: qltools diskimage -[options] [filename]\n\n");
  97.     fprintf(stderr,"options:\n\n");
  98.     fprintf(stderr,"-d      list directory\n");
  99.     fprintf(stderr,"-i      list info\n");
  100.     fprintf(stderr,"-m      list disk map\n");
  101.     fprintf(stderr,"-c      list conversion table of sectors\n");
  102.     fprintf(stderr,"-nFN    output file number NF in the directory listing\n\n");
  103.     fprintf(stderr,"diskimage is either a file with the image of a QL format disk\n");
  104.     fprintf(stderr,"or a unix device with a ql disk inserted in it (/dev/fd...)\n\n");
  105.  
  106.     fprintf(stderr,"Giuseppe Zanetti\n");
  107.     fprintf(stderr,"via Vergani, 11 - 35031 Abano Terme (Pdaova) ITALY\n");
  108.     fprintf(stderr,"e-mail: beppe@sabrina.dei.unipd.it\n");
  109.     exit(1);
  110. }
  111.  
  112.  
  113. void print_info()
  114. {
  115.     int i;
  116.  
  117.     printf("Disk Id          : ");
  118.  
  119.     for (i=0;i<4;i++)
  120.     {
  121.         printf("%c",b0[i]);
  122.     }
  123.     printf("\n");
  124.  
  125.     printf("Disk Label       : ");
  126.  
  127.     for (i=0;i<10;i++)
  128.     {
  129.         printf("%c",b0[4+i]);
  130.     }
  131.     printf("\n");
  132.  
  133.     printf("Sectors per track: %i\n",gsectors);
  134.     printf("sectors per cyl. : %i\n",wrd(b0+28));
  135.     printf("number of cylind.: %i\n",gtracks);
  136.     printf("allocation block : %i\n",wrd(b0+32));
  137.     printf("sector offset/cyl: %i\n",goffset);
  138.  
  139.     printf("free sectors     : %i\n",wrd(b0+20));
  140.     printf("good sectors     : %i\n",wrd(b0+22));
  141.     printf("total sectors    : %i\n",wrd(b0+24));
  142.  
  143.     printf("directory is     : %i sectors and %u bytes\n",bleod,byeod);
  144.  
  145.     printf("\nlogical-to-physical sector mapping table:\n\n");
  146.     for (i=0;i<18;i++) printf("%u ",ltp[i]);
  147.     printf("\n");
  148.  
  149.     printf("\nphysical-to-logical sector mapping table:\n\n");
  150.     for (i=0;i<18;i++) printf("%u ",ptl[i]);
  151.     printf("\n");
  152. }
  153.  
  154. void print_dir()
  155. {
  156.     int d,i;
  157.     char c;
  158.  
  159.         for (i=0;i<10;i++)
  160.         {
  161.                 printf("%c",b0[4+i]);
  162.         }
  163.         printf("\n");
  164.  
  165.     printf("%i/%i sectors.\n\n",wrd(b0+20),wrd(b0+22));
  166.  
  167.     for (d=64;d <512*bleod+byeod;d+=64)
  168.     {
  169.         printf("%3i : ",d/64);
  170.  
  171.         for (i=0;i<wrd(pdir+d+14);i++)
  172.         {
  173.             c=*(pdir+d+16+i);
  174.  
  175.             printf("%c",c);
  176.         }
  177.  
  178.         for(i=0;i<38-wrd(pdir+d+14);i++) printf(" ");
  179.  
  180.         switch(*(pdir+d+5))
  181.         {
  182.             case 0: printf("          "); break;
  183.             case 1: printf("executable"); break;
  184.             case 2: printf("relocable "); break;
  185.             default:printf("bad type  "); break;
  186.         }
  187.  
  188.         printf("    %ld\n",lwrd(pdir+d) - 64);
  189.  
  190.     }
  191. }
  192.  
  193. void make_convtable(verbose)
  194. int verbose;
  195. {
  196.     int i,si,tr,se,ls,ps,uxs;
  197.  
  198.     if (verbose)
  199.     {
  200.         printf("\nCONVERSION TABLE\n\n");
  201.         printf("logic\ttrack\tside\tsector\tunix_dev\n\n");
  202.     }
  203.  
  204.     for(i=0;i<gtracks*gsectors*gsides;i++)
  205.     {
  206.         tr=i / (gsectors*gsides);
  207.         ls=i % (gsectors*gsides);
  208.  
  209.         ps = ltp[ls];
  210.  
  211.         si=(ps & 0x80) != 0;
  212.  
  213.         ps &= 0x7F;
  214.  
  215.         ps += goffset*tr;
  216.         se = ps % gsectors;
  217.  
  218.         uxs = tr*gsectors*gsides+gsectors*si+se;
  219.  
  220.         convtable[i] = uxs;
  221.  
  222.         if (verbose)
  223.         {
  224.             printf("%i\t%i\t%i\t%i\t%i\n",i,tr,si,se,uxs);
  225.         }
  226.     }
  227. }
  228.  
  229. int wrd(wp)
  230. char *wp;
  231. {
  232.     int r;
  233.  
  234.     r=*(wp)*256 + *(wp+1);
  235.  
  236.     return r;
  237. }
  238.  
  239.  
  240. int read_block0()
  241. {
  242.     int i;
  243.  
  244.     fseek(f,0,SEEK_SET);
  245.     fread(b0,512,1,f);
  246.  
  247.     fseek(f,512*3,SEEK_SET);
  248.     fread(b0+512,512,1,f);
  249.  
  250.     fseek(f,512*6,SEEK_SET);
  251.     fread(b0+1024,512,1,f);
  252.  
  253.     /* read ptl and ptl tables */
  254.  
  255.     for (i=0;i<18;i++)
  256.     {
  257.         ltp[i] = *(b0+40+i);
  258.         ptl[i] = *(b0+58+i);
  259.     }
  260.  
  261.     return(0);
  262. }
  263.  
  264. int read_block(p,num)
  265. char *p;
  266. int num;
  267. {
  268.     int i;
  269.     int r=0;
  270.  
  271.     for(i=0;i<3;i++)
  272.     {
  273.         fseek(f,(512*convtable[num*3+i]),SEEK_SET);
  274.         r += fread(p+512*i,512,1,f);
  275.     }
  276.  
  277.     return(r);
  278. }
  279.  
  280.  
  281. long int match_file(fname)
  282. char *fname;
  283. {
  284.     int d,i,match,len;
  285.     long int r=0L;
  286.     char c;
  287.  
  288.     len=strlen(fname);
  289.  
  290.     for (d=64;d <512*bleod+byeod;d+=64)
  291.     {
  292.         match=1;
  293.  
  294.         if (wrd(pdir+d+14) == len)
  295.         {
  296.             for (i=0;i<len;i++)
  297.             {
  298.                 c=*(pdir+d+16+i);
  299.  
  300.                 if (c != fname[i]) match=0;
  301.             }
  302.  
  303.             if (match)
  304.             {
  305.                 r=d/64;
  306.                 break;
  307.             }
  308.         }
  309.     }
  310.  
  311.     return(r);
  312. }
  313.  
  314. main(argc,argv)
  315. int argc;
  316. char * argv[];
  317. {
  318.     int i;
  319.     unsigned long int finfofile, finfoblk;
  320.     unsigned char *base;
  321.  
  322.     int argdir,arginfo,argfnum,argmap,argconv;
  323.     char argfname[255];
  324.  
  325. #ifdef THINK_C
  326.     argc=ccommand(&argv);
  327. #endif
  328.  
  329.     argdir=arginfo=argfnum=argmap=argconv=0;
  330.     strcpy(argfname,"");
  331.  
  332.     if (argc < 2)
  333.     {
  334.         usage("too few parameters");
  335.     }
  336.  
  337.     for(i=2;i<argc;i++)
  338.     {
  339.         if (argv[i][0] == '-')
  340.         {
  341.             switch(argv[i][1])
  342.             {
  343.                 case 'd': argdir=1; break;
  344.                 case 'i': arginfo=1; break;
  345.                 case 'm': argmap=1; break;
  346.                 case 'c': argconv=1; break;
  347.                 case 'n': argfnum=atol(argv[i]+2); break;
  348.                 default: usage("bad option"); break;
  349.             }
  350.         }
  351.         else
  352.         {
  353.             strcpy(argfname,argv[i]);
  354.         }
  355.     }
  356.  
  357.     f=fopen(argv[1],"rb");
  358.  
  359.     if (f==NULL)
  360.     {
  361.         usage("bad image file or device");
  362.     }
  363.  
  364.     read_block0();
  365.  
  366.     gsides=2;
  367.     gtracks=wrd(b0+30);
  368.     gsectors=wrd(b0+26);
  369.     goffset=wrd(b0+38);
  370.     bleod=wrd(b0+34);
  371.     byeod=wrd(b0+36);
  372.     pdir=(unsigned char *) malloc(512*(bleod+1));
  373.     
  374.     make_convtable(argconv);
  375.  
  376.  
  377.     /* read the directory map */
  378.  
  379.     if (argmap)
  380.     {
  381.         printf("\nblock\tfile\tpos\n\n");
  382.     }
  383.  
  384.     for (i=0;i<(wrd(b0+28)*wrd(b0+30))/wrd(b0+32);i++)
  385.     {
  386.         base=b0+0x4C+20+i*3;
  387.  
  388.         finfofile= (unsigned long int) (*(base) * 0x10) + (unsigned long int) ((*(base+1) >> 4) & 0x0F) ;
  389.         finfoblk= (*(base+1) & 0x0F)*0x100 + *(base+2);
  390.  
  391.  
  392.         if (finfofile == 0x00)
  393.         {
  394.                                     read_block(pdir+512*3*finfoblk,i);
  395.         }
  396.  
  397.         if (argmap)
  398.         {
  399.             printf("%d\t%ld\t%ld\t",i,finfofile,finfoblk);
  400.  
  401.             switch(finfofile)
  402.             {
  403.                 case 0x000: printf("directory %i\n",finfoblk); break;
  404.                 case 0xF80: printf("map\n"); break;
  405.                 case 0xFDF: printf("unused\n"); break;
  406.                 case 0xFEF: printf("bad\n"); break;
  407.                 case 0xFFF: printf("not existent\n"); break;
  408.                 default: printf("\n"); break;
  409.             }
  410.         }
  411.     }
  412.  
  413.     if (arginfo) print_info();
  414.     if (argdir) print_dir();
  415.     if (argfnum != 0) cat_file(argfnum);
  416.     if (strcmp(argfname,"") != 0)
  417.     {
  418.         argfnum=match_file(argfname);
  419.  
  420.         if (argfnum == 0)
  421.         {
  422.             fprintf(stderr,"file not found\n");
  423.             exit(2);
  424.         }
  425.  
  426.         cat_file(argfnum);
  427.     }
  428.  
  429.     fclose(f);
  430.     return (0);
  431. }
  432.  
  433. /*
  434.  
  435.  
  436.     What exactly do you want to know?  I don't know about the
  437. 3.2MB format, but I can tell you about 720k.  Allocation blocks are 3
  438. sectors long (normally.  This can be changed) and the block 0
  439. (consisting of sectors 0, 3 and 6 of side 0 on cylinder 0) contains
  440. the mapping info.  The first 96 bytes are used as follows:
  441.        OFFSET  SIZE           VALUE
  442.     $00    .L        $514C3541
  443.     $04    10 bytes    disk label
  444.     $0E    .W        random number (created by FORMAT)
  445.     $10    .L        #writes to this disk
  446.     $14    .W        #free sectors
  447.     $16    .W        #good sectors
  448.     $18    .W        total sectors
  449.     $1A    .W        #sectors per track (9)
  450.     $1C    .W        #sectors per cylinder (18 for DS)
  451.     $1E    .W        number of cylinders (80)
  452.     $20    .W        size of allocation block (3)
  453.     $22    .W        block number for end-of-directory
  454.     $24    .W        byte number of end-of-directory
  455.     $26    .W        sector offset/cylinder
  456.     $28    18 bytes    logical-to-physical sector mapping table
  457.     $3A    18 bytes    physical-to-logical sector mapping table
  458.     $4C    20 bytes    unused
  459.  
  460. The rest of the block consists of pairs of 12-bit values (24 bits for
  461. each block on a fully formatted, 80 track, double sided disk) the
  462. first of which contains the file number which that block belongs to,
  463. the seconds holds the position of this block within that file.  Some
  464. special file numbers are used for the mapping block itself ($F80),
  465. unused blocks ($FDF), bad blocks ($FEF) and non-existant blocks ($FFF)
  466. and the block-number of unused, bad and non-existant blocks is always
  467. $FFF (but when a file is deleted, only the top byte is set to $FD)
  468. the map is $F80 000 - it consists of one block!  The directory
  469. is file number $000, and all other files have numbers corresponding to
  470. their positions in the directory (file $001 is the first, $002 is the
  471. second, etc.)
  472.     The "logical-to-physical sector mapping table" contains a byte
  473. for each sector on a cylinder (18) corresponding to the physical
  474. sector number (0 to 8, with the MSB set for sectors on side 1) for
  475. each logical file sector.  This table is always "0 3 6 128 131 134 1 4
  476. 7 129 132 135 2 5 8 130 133 136" (unless someone has changed it)
  477. meaning sectors 0, 3, 6 of side 0 are used first, then sectors 0, 3, 6
  478. of side 1, then sectors 1, 4, 7 of side 0, etc.  _BUT_ the sector
  479. number is offset by an amount depending on the cylinder number (the
  480. numbers above are correct for cylinder 0, but the "sector
  481. offset/track" value is added (mod 9) for each cylinder.  This value is
  482. usually 5, so the table values are correct again at cylinder 9)
  483.     The "physical-to-logical sector mapping table" contains 9
  484. entries for each side of the disk, containing the logical sector
  485. numbers of the physical sectors on the disk.  It is "0 6 12 1 7 13 2 8
  486. 14" for side 0 and "3 9 15 4 1 16 5 11 17" for side 1 (that is, for
  487. side 0, phys. sector 0 contains log. sector 0, phys. sector 1 contains
  488. log. sector 6, ...) again, this is affected by the "sector
  489. offset/track".
  490.  
  491.     The directory consists of 64 '0's ($30 bytes, not $00 bytes.
  492. I don't know what they're for) followed by a 64 byte entry for each
  493. file, in the following format:
  494.        OFFSET  SIZE           USE
  495.     $00    .L        file length
  496.     $04    .B        unused
  497.     $05    .B        file type
  498.     $06    .L        dataspace (for exec'able programs)
  499.     $0A    .L        unused
  500.     $0E    .W        length of file name
  501.     $10    36 bytes    file name
  502.     $34    .L        file update date
  503.     $38    .L        unused.  Supposed to be reference date.
  504.     $3C    .L        unused.  Supposed to be backup date.
  505.  
  506. The first 64 bytes in the first block of each file contains a copy of
  507. the directory entry, but most of the information in it is not correct
  508. (the name is OK, though)
  509.  
  510.     Hope that helps.
  511.  
  512.                             - Paul
  513.  
  514. */
  515.  
  516.